import validation
import unittest

class ValidationResultConstructorTestCase(unittest.TestCase):
	def testConsructs(self):
		validation_result = validation.ValidationResult("original value", "sanitized value")

	def testConstructorSetsExpectedFields(self):
		validation_result = validation.ValidationResult("original value", "sanitized value")
		assert validation_result.original_value == "original value", "expected 'original_value' field to be set"
		assert validation_result.value == "sanitized value", "expected 'value' field to be set"

	def testConstructorWithErrorsDoesNotSetValue(self):
		validation_result = validation.ValidationResult("original value", "sanitized value", opt_errors=["error a", "error b"])
		assert validation_result.original_value == "original value", "expected 'original_value' field to be set"
		assert validation_result.value == None, "expected 'value' field to be None"
		assert validation_result.errors == ["error a", "error b"], "expected 'errors' field to be set"

class ValidationResultIsValidTestCase(unittest.TestCase):
	def testIsValidReturnsTrue(self):
		assert validation.ValidationResult("value", "value").is_valid() == True, "expected True"

	def testIsValidReturnsFalseOnError(self):
		assert validation.ValidationResult("value", opt_errors=["error"]).is_valid() == False, "expected False"
		
class ValidationResultLastErrorTestCase(unittest.TestCase):
	def testGetLastErrorReturnsNoneIfNoErrors(self):
		assert validation.ValidationResult("value", "value").get_last_error() == None, "expected None"

	def testGetLastErrorReturnsError(self):
		errors = ["error"]
		assert validation.ValidationResult("value", opt_errors=errors).get_last_error() == "error", "expected 'error'"

	def testGetLastErrorReturnsLastError(self):
		errors = ["error a", "error b", "error c"]
		assert validation.ValidationResult("value", opt_errors=errors).get_last_error() == "error c", "expected 'error c'"

class MockValidator(object):
	def __init__(self, result_value, errors, opt_key=None):
		self.result_value = result_value
		self.errors = errors
		self.validate_called = False
		self.key_ = opt_key

	def validate(self, value):
		self.validate_called = True
		return validation.ValidationResult(value, self.result_value, self.errors)

class ValidationChainConstructorTestCase(unittest.TestCase):
	def testConstructs(self):
		validation_chain = validation.ValidationChain([])

	def testConstructorSetsExpectedFields(self):
		validators = [
			MockValidator("value a", []),
			MockValidator("value b", ["error"]),
		]
		validation_chain = validation.ValidationChain(validators)
		assert len(validation_chain.validators) == 2, "expected 'validators' to be set"

class ValidationChainValidateTestCase(unittest.TestCase):
	def testNoValidatorsReturnsSuccess(self):
		validation_chain = validation.ValidationChain([])
		validation_result = validation_chain.validate("test value")
		assert validation_result.is_valid(), "expected True"
		assert validation_result.value == "test value", "expected 'test value'"

	def testAllValidatorsSuccess(self):
		validators = [
			MockValidator("value middle", []),
			MockValidator("value end", []),
		]
		validation_chain = validation.ValidationChain(validators)
		validation_result = validation_chain.validate("value start")
		assert validation_result.is_valid(), "expected True"
		assert validation_result.value == "value end", "expected 'value end'"
		assert validators[0].validate_called == True, "expected validate() to be called"
		assert validators[1].validate_called == True, "expected validate() to be called" 

	def testValidatorFailureInChain(self):
		validators = [
			MockValidator("value middle", ["error"]),
			MockValidator("value end", []),
		]
		validation_chain = validation.ValidationChain(validators)
		validation_result = validation_chain.validate("value start")
		assert validation_result.is_valid() == False, "expected False"
		assert validation_result.value == None, "expected None"
		assert validation_result.get_last_error() == "error", "expected 'error'"
		assert validators[0].validate_called == True, "expected validate() to be called"
		assert validators[1].validate_called == False, "expected validate() to not be called" 

class MockValidationResult(object):
	def __init__(self, is_valid, opt_value=None, opt_key=None):
		self.is_valid_ = is_valid
		self.is_valid_called = False
		self.value = opt_value
		self.key_ = opt_key

	def is_valid(self):
		self.is_valid_called = True
		return self.is_valid_

class ValidationResponseConstructorTestCase(unittest.TestCase):
	def testConstructs(self):
		validation_response = validation.ValidationResponse()

class ValidationResponseAppendResultTestCase(unittest.TestCase):
	def testAppendResultAddsToResults(self):
		validation_result = MockValidationResult(True)
		validation_response = validation.ValidationResponse();
		assert len(validation_response.results) == 0, "expected 'results' to be empty"
		validation_response.append_result("testkey", validation_result)
		assert len(validation_response.results) == 1, "expected 'results' to have increased"
		assert validation_response.results.has_key("testkey"), "expected 'results' to contain key"

	def testAppendResultDuplicateKeyThrows(self):
		validation_response = validation.ValidationResponse()
		validation_response.append_result("testkey", MockValidationResult(True))
		try:
			validation_response.append_result("testkey", MockValidationResult(True))
		except KeyError:
			pass
		else:
			self.fail("expected a KeyError")

class ValidationResponseIsValidTestCase(unittest.TestCase):
	def testIsValidReturnsSuccessIfEmptyResults(self):
		validation_response = validation.ValidationResponse()
		assert validation_response.is_valid() == True, "expected True"

	def testIsValidReturnsSuccessWithOneValidResult(self):
		validation_result = MockValidationResult(True)
		validation_response = validation.ValidationResponse()
		validation_response.append_result("resultA", validation_result)
		assert validation_response.is_valid() == True, "expected True"
		assert validation_result.is_valid_called == True, "expected 'is_valid()' to be called"

	def testIsValidReturnsFailureWithOneInvalidResult(self):
		validation_result = MockValidationResult(False)
		validation_response = validation.ValidationResponse()
		validation_response.append_result("resultA", validation_result)
		assert validation_response.is_valid() == False, "expected False"
		assert validation_result.is_valid_called == True, "expected 'is_valid()' to be called"

	def testIsValidReturnsSuccessWithManyValidResults(self):
		validation_results = [
			MockValidationResult(True),
			MockValidationResult(True),
			MockValidationResult(True),
		]
		validation_response = validation.ValidationResponse()
		validation_response.append_result("resultA", validation_results[0])
		validation_response.append_result("resultB", validation_results[1])
		validation_response.append_result("resultC", validation_results[2])
		assert validation_response.is_valid() == True, "expected True"
		assert validation_results[0].is_valid_called == True, "expected 'is_valid()' to be called"
		assert validation_results[1].is_valid_called == True, "expected 'is_valid()' to be called"
		assert validation_results[2].is_valid_called == True, "expected 'is_valid()' to be called"
		
	def testIsValidReturnsFailureWithOneInvalidResultInManyResults(self):
		validation_results = [
			MockValidationResult(True),
			MockValidationResult(False),
			MockValidationResult(True),
		]
		validation_response = validation.ValidationResponse()
		validation_response.append_result("resultA", validation_results[0])
		validation_response.append_result("resultB", validation_results[1])
		validation_response.append_result("resultC", validation_results[2])
		assert validation_response.is_valid() == False, "expected False"

		# We cannot know for sure which order the results are checked because they are in a dict.
		# Therefore, the only one we can be sure about is the one that was a failure.
		assert validation_results[1].is_valid_called == True, "expected 'is_valid()' to be called"

class ValidationResponseGetTestCase(unittest.TestCase):
	def testGetWithNoResultsReturnsNone(self):
		validation_response = validation.ValidationResponse()
		validation_result = validation_response.get("somekey")
		assert validation_result == None, "expected None"

	def testGetWithUnknownKeyReturnsNone(self):
		validation_response = validation.ValidationResponse()
		validation_response.append_result("resultA", MockValidationResult(True))
		validation_response.append_result("resultB", MockValidationResult(True))
		validation_result = validation_response.get("resultC")
		assert validation_result == None, "expected None"

	def testGetWithValidKeyReturnsResult(self):
		validation_response = validation.ValidationResponse()
		validation_response.append_result("resultA", MockValidationResult(True, opt_key="keyA"))
		validation_response.append_result("resultB", MockValidationResult(True, opt_key="keyB"))
		validation_response.append_result("resultC", MockValidationResult(True, opt_key="keyC"))
		validation_result = validation_response.get("resultB")
		assert validation_result != None, "expected not None"
		assert validation_result.key_ == "keyB", "expected the correct object"

class ValidationResponseGetValueTestCase(unittest.TestCase):
	def testGetValueWithNoResultsAndNoDefaultReturnsNone(self):
		validation_response = validation.ValidationResponse()
		assert validation_response.get_value("somekey") == None, "expected None"

	def testGetValueWithNoResultsReturnsDefault(self):
		validation_response = validation.ValidationResponse()
		assert validation_response.get_value("somekey", "somedefault") == "somedefault", "expected default"

	def testGetValueWithUnknownKeyAndNoDefaultReturnsNone(self):
		validation_response = validation.ValidationResponse()
		validation_response.append_result("resultA", MockValidationResult(True))
		validation_response.append_result("resultB", MockValidationResult(True))
		assert validation_response.get_value("resultC") == None, "expected None"

	def testGetValueWithUnknownKeyReturnsDefault(self):
		validation_response = validation.ValidationResponse()
		validation_response.append_result("resultA", MockValidationResult(True))
		validation_response.append_result("resultB", MockValidationResult(True))
		assert validation_response.get_value("resultC", "somedefault") == "somedefault", "expected default"

	def testGetValueWithValidKeyReturnsValue(self):
		validation_response = validation.ValidationResponse()
		validation_response.append_result("resultA", MockValidationResult(True, opt_value="valueA"))
		validation_response.append_result("resultB", MockValidationResult(True, opt_value="valueB"))
		validation_response.append_result("resultC", MockValidationResult(True, opt_value="valueC"))
		assert validation_response.get_value("resultB") == "valueB", "expected value"

class MockRequest(object):
	def __init__(self, arguments, opt_key=None):
		self.arguments = arguments
		self.key_ = opt_key
		
	def get(self, key, opt_default):
		return self.arguments.get(key, opt_default)

class ValidationRequestConstructorTestCase(unittest.TestCase):
	def testConstructs(self):
		validation_request = validation.ValidationRequest()

class ValidationRequestExpectFieldTestCase(unittest.TestCase):
	def testExpectFieldAddsToFields(self):
		request = MockRequest({})
		validation_request = validation.ValidationRequest()
		assert len(validation_request.fields) == 0, "expected 'fields' to be empty"
		validation_request.expect_field("test field", [])
		assert len(validation_request.fields) == 1, "expected 'fields' to increase"

class ValidationRequestValidateTestCase(unittest.TestCase):
	def testValidateWithNoArgumentsReturnsValidResponse(self):
		request = MockRequest({})
		validation_request = validation.ValidationRequest()
		validation_response = validation_request.validate(request)
		assert validation_response.is_valid() == True, "expected True"

	def testValidateUnexpectedFieldsAreIgnored(self):
		request = MockRequest({"fieldA": "valueA"})
		validation_request = validation.ValidationRequest()
		validation_response = validation_request.validate(request)
		assert validation_response.is_valid() == True, "expected True"
		assert validation_response.get("fieldA") == None, "expected None"

	def testValidateExpectedFieldIsValidated(self):
		request = MockRequest({"fieldA": "valueA"})
		validation_request = validation.ValidationRequest()
		validation_request.expect_field("fieldA", [MockValidator("valueAChanged", [])])
		validation_response = validation_request.validate(request)
		assert validation_response.is_valid() == True, "expected True"
		assert validation_response.get_value("fieldA") == "valueAChanged"

	def testValidateExpectedFieldsAreValidated(self):
		request = MockRequest({"fieldA": "valueA", "fieldB": "valueB", "fieldC": "valueC"})
		validation_request = validation.ValidationRequest()
		validation_request.expect_field("fieldA", [MockValidator("valueAChanged", ["error"])])
		validation_request.expect_field("fieldB", [MockValidator("valueBChanged", [])])
		validation_response = validation_request.validate(request)
		assert validation_response.is_valid() == False, "expected False"
		assert validation_response.get_value("fieldA") == None, "expected None"
		assert validation_response.get("fieldA") != None, "expected not None"
		assert validation_response.get_value("fieldB") == "valueBChanged", "expected value"
		assert validation_response.get("fieldB") != None, "expected not None"
		assert validation_response.get_value("fieldC") == None, "expected None"
		assert validation_response.get("fieldC") == None, "expected None"

class ValidationErrorConstructorTestCase(unittest.TestCase):
	def testConstructs(self):
		validation_error = validation.ValidationError("Some message")

	def testConstructorSetsExpectedFields(self):
		validation_error = validation.ValidationError("Some message")
		assert validation_error.message == "Some message", "expected 'message' to be set"

class ValidatorConstructorTestCase(unittest.TestCase):
	def testConstructs(self):
		validator = validation.Validator()
		
class ValidatorValidateTestCase(unittest.TestCase):
	def testValidateNoneReturnsNone(self):
		validator = validation.Validator()
		validation_result = validator.validate(None)
		assert validation_result != None, "expected object"
		assert validation_result.value == None, "expected None"

	def testValidateValueReturnsValue(self):
		validator = validation.Validator()
		validation_result = validator.validate("test")
		assert validation_result != None, "expected object"
		assert validation_result.value == "test", "expected value"

class RequiredValidatorConstructorTestCase(unittest.TestCase):
	def testConstructs(self):
		validator = validation.RequiredValidator()

class RequiredValidatorValidateTestCase(unittest.TestCase):
	def testValidateNoneFails(self):
		validator = validation.RequiredValidator()
		validation_result = validator.validate(None)
		assert validation_result != None, "expected object"
		assert len(validation_result.errors) == 1, "expected one validation error"

	def testValidateEmptyStringFails(self):
		validator = validation.RequiredValidator()
		validation_result = validator.validate("")
		assert validation_result != None, "expected object"
		assert len(validation_result.errors) == 1, "expected one validation error"

	def testValidateEmptyListFails(self):
		validator = validation.RequiredValidator()
		validation_result = validator.validate([])
		assert validation_result != None, "expected object"
		assert len(validation_result.errors) == 1, "expected one validation error"

	def testValidateAnyValueSucceeds(self):
		validator = validation.RequiredValidator()
		validation_result = validator.validate("test")
		assert validation_result != None, "expected object"
		assert validation_result.value == "test", "expected value"
		assert len(validation_result.errors) == 0, "expected no validation errors"

class StringRegexValidatorConstructorTestCase(unittest.TestCase):
	def testConstructs(self):
		validator = validation.StringRegexValidator("^.*$")

	def testConstructorSetsExpectedField(self):
		validator = validation.StringRegexValidator("^.*$")
		assert validator.regex == "^.*$", "expected value"

class StringRegexValidatorValidateTestCase(unittest.TestCase):
	def testValidateNoneSucceedsAlways(self):
		validator = validation.StringRegexValidator("^.+$")
		validation_result = validator.validate(None)
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"

	def testValidateRegexMismatchFails(self):
		validator = validation.StringRegexValidator("^\d$")
		validation_result = validator.validate("a")
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == False, "expected False"
		assert len(validation_result.errors) == 1, "expected one validation error" 

	def testValidateRegexMatchSucceeds(self):
		validator = validation.StringRegexValidator("^\d$")
		validation_result = validator.validate("1")
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"

class StringExactMatchValidatorConstructorTestCase(unittest.TestCase):
	def testConstructs(self):
		validator = validation.StringExactMatchValidator("test")

	def testConstructorSetsExpectedFields(self):
		validator = validation.StringExactMatchValidator("test")
		assert validator.match == "test", "expected value"

class StringExactMatchValidatorValidateTestCase(unittest.TestCase):
	def testValidateNoneSucceedsAlways(self):
		validator = validation.StringExactMatchValidator("test")
		validation_result = validator.validate(None)
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"

	def testValidateMismatchFails(self):
		validator = validation.StringRegexValidator("hello")
		validation_result = validator.validate("world")
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == False, "expected False"
		assert len(validation_result.errors) == 1, "expected one validation error" 

	def testValidateMatchSucceeds(self):
		validator = validation.StringRegexValidator("hello")
		validation_result = validator.validate("hello")
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"

class StringLengthValidatorConstructorTestCase(unittest.TestCase):
	def testConstructs(self):
		validator = validation.StringLengthValidator(10, 20)

	def testConstructorSetsExpectedFields(self):
		validator = validation.StringLengthValidator(10, 20)
		assert validator.min == 10, "expected 'min' to be set"
		assert validator.max == 20, "expected 'max' to be set"

class StringLengthValidatorValidateTestCase(unittest.TestCase):
	def testValidateNoneSucceedsAlways(self):
		validator = validation.StringLengthValidator(10, 20)
		validation_result = validator.validate(None)
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"

	def testValidateStringTooShortFails(self):
		validator = validation.StringLengthValidator(5, 10)
		validation_result = validator.validate("test")
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == False, "expected False"
		assert len(validation_result.errors) == 1, "expected one validation error" 

	def testValidateStringTooLongFails(self):
		validator = validation.StringLengthValidator(5, 10)
		validation_result = validator.validate("hello world")
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == False, "expected False"
		assert len(validation_result.errors) == 1, "expected one validation error" 

	def testValidateStringWithLengthBetweenBoundsSucceeds(self):
		validator = validation.StringLengthValidator(5, 10)
		validation_result = validator.validate("testing")
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"

	def testValidateStringWithLengthEqualToLowerBoundSucceeds(self):
		validator = validation.StringLengthValidator(7, 10)
		validation_result = validator.validate("testing")
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"

	def testValidateStringWithLengthEqualToUpperBoundSucceeds(self):
		validator = validation.StringLengthValidator(0, 7)
		validation_result = validator.validate("testing")
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"

class StringEnumerationValidatorConstructorTestCase(unittest.TestCase):
	def testConstructs(self):
		validator = validation.StringEnumerationValidator(["a", "b"])

	def testConstructorSetsExpectedFields(self):
		validator = validation.StringEnumerationValidator(["a", "b"])
		assert validator.values == ["a", "b"], "expected 'values' to be set"

class StringEnumerationValidatorValidateTestCase(unittest.TestCase):
	def testValidateNoneSucceedsAlways(self):
		validator = validation.StringEnumerationValidator(["a", "b"])
		validation_result = validator.validate(None)
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"

	def testValidateEmptyValuesFailsAlways(self):
		validator = validation.StringEnumerationValidator([])
		validation_result = validator.validate("world")
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == False, "expected False"
		assert len(validation_result.errors) == 1, "expected one validation error" 

	def testValidateEmptyStringNotInValuesFails(self):
		validator = validation.StringEnumerationValidator(["a", "b"])
		validation_result = validator.validate("")
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == False, "expected False"
		assert len(validation_result.errors) == 1, "expected one validation error" 

	def testValidateStringNotInValuesFails(self):
		validator = validation.StringEnumerationValidator(["a", "b"])
		validation_result = validator.validate("c")
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == False, "expected False"
		assert len(validation_result.errors) == 1, "expected one validation error" 

	def testValidateStringInValuesSucceeds(self):
		validator = validation.StringEnumerationValidator(["a", "b"])
		validation_result = validator.validate("b")
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"

class IntegerValidatorConstructorTestCase(unittest.TestCase):
	def testConstructs(self):
		validator = validation.IntegerValidator()

class IntegerValidatorValidateTestCase(unittest.TestCase):
	def testValidateNoneSucceedsAlways(self):
		validator = validation.IntegerValidator()
		validation_result = validator.validate(None)
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"

	def testValidateEmptyStringSucceedsAlways(self):
		validator = validation.IntegerValidator()
		validation_result = validator.validate("")
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"

	def testValidateInvalidIntegerStringFails(self):
		validator = validation.IntegerValidator()
		validation_result = validator.validate("abcdefg")
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == False, "expected False"
		assert len(validation_result.errors) == 1, "expected one validation error"

	def testValidateValidIntegerStringSucceeds(self):
		validator = validation.IntegerValidator()
		validation_result = validator.validate("12345")
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"
		
	def testValidateReturnsInteger(self):
		validator = validation.IntegerValidator()
		validation_result = validator.validate("12345")
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"
		assert validation_result.value == 12345, "expected an integer"

class IntegerRangeValidatorConstructorTestCase(unittest.TestCase):
	def testConstructs(self):
		validator = validation.IntegerRangeValidator()

class IntegerRangeValidatorValidateTestCase(unittest.TestCase):
	def testValidateNoneSucceedsAlways(self):
		validator = validation.IntegerRangeValidator(10, 20)
		validation_result = validator.validate(None)
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"

	def testValidateIntegerTooLowFails(self):
		validator = validation.IntegerRangeValidator(10, 20)
		validation_result = validator.validate(5)
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == False, "expected False"
		assert len(validation_result.errors) == 1, "expected one validation error"

	def testValidateIntegerTooHighFails(self):
		validator = validation.IntegerRangeValidator(10, 20)
		validation_result = validator.validate(25)
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == False, "expected False"
		assert len(validation_result.errors) == 1, "expected one validation error"

	def testValidateIntegerWithinBoundsSucceeds(self):
		validator = validation.IntegerRangeValidator(10, 20)
		validation_result = validator.validate(15)
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"

	def testValidateIntegerAtLowerBoundSucceeds(self):
		validator = validation.IntegerRangeValidator(10, 20)
		validation_result = validator.validate(10)
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"

	def testValidateIntegerAtUpperBoundSucceeds(self):
		validator = validation.IntegerRangeValidator(10, 20)
		validation_result = validator.validate(20)
		assert validation_result != None, "expected object"
		assert validation_result.is_valid() == True, "expected True"

if __name__ == "__main__":
	unittest.main()
